# -*- coding: utf-8 -*-
""" The LAS Object module.

Read and write LAS files

  :Author:
    - 2010-2012 Nicola Creati and Roberto Vidmar

  :Revision:  $Revision: 8 $
              $Date: 2013-02-01 10:12:57 +0100 (Fri, 01 Feb 2013) $

  :Copyright: 2010-2012
              Nicola Creati <ncreati@inogs.it>
              Roberto Vidmar <rvidmar@inogs.it>

  :License: MIT/X11 License (see :download:`LICENSE.txt
                             <../../LICENSE.txt>`)
"""
#===============================================================================
import os

# Local libraries
from core import Header, getLongest
from points import Points
from lasExceptions import LasException

#===============================================================================
class LasObject(object):
  """ The LAS file class
  """
  # Keep trace of opened files
  _lock = []

  def __init__(self, filename, mode='r', *args, **kargs):
    """ Create a new :class:`LasObject` instance.

      :param filename: LAS file to open
      :type filename: unicode
      :param mode: file mode ('r' or 'w')
      :type mode: string

      Optional kargs will be passed to Header
    """
    self._filename = os.path.abspath(filename)

    # Check if file is already opened
    for f in self._lock:
      if f == self._filename:
        raise IOError(
          "File %s is already in use. Close the file or delete "
          "the reference to it" % self._filename)
    self._lock.append(self._filename)

    # Now open the file
    if mode == 'w':
      # Write mode:  Binary mode must be explicitly set on Window
      self._fid = open(self._filename, 'wb')
    else:
      # Read mode: Binary mode must be explicitly set on Window
      self._fid = open(self._filename, 'rb')

    self._header = Header(self, *args, **kargs)
    self._points = Points(self)

  def __repr__(self):
    """ Return string representation of the :class:`LasObject`
    """
    title = '%s:\n  Filename: %s\n' % (self.__class__.__name__, self._filename)
    headerRepr = repr(self._header) + '\n'
    vlrRepr = "\n".join([repr(vlr) for vlr in self._header.varLengthRecords()])
    lenmax = max(getLongest(headerRepr), getLongest(vlrRepr))
    title += '-' * (lenmax + 2) + '\n'
    return title + headerRepr + vlrRepr

#-------------------------------------------------------------------------------
# Public methods
#-------------------------------------------------------------------------------
  def fid(self):
    """ Return LAS file identifier

      :returns: LAS file identifier
      :rtype: :class:`file`
    """
    return self._fid

  def bbox(self):
    """ Return bounding box [xmin, xmax, ymin, ymax, zmin, zmax]

      :returns: bounding box [xmin, xmax, ymin, ymax, zmin, zmax]
      :rtype: tuple
    """
    return (
      self._header.getXmin(), self._header.getXmax(),
      self._header.getYmin(), self._header.getYmax(),
      self._header.getZmin(), self._header.getZmax())

  def close(self):
    """ Close las file and remove lock
    """
    self._lock.remove(self._filename)
    self._fid.close()

  def filename(self):
    """ Return Las filename

      :returns: Las filename
      :rtype: string
    """
    return self._filename

  def height(self):
    """ Return Las dataset y range

      :returns: Las dataset y range
      :rtype: float
    """
    y0, y1 = self._header.yRange()
    return y1 - y0

  def width(self):
    """ Return dataset x range

      :returns: Las dataset x range
      :rtype: float
    """
    x0, x1 = self._header.xRange()
    return x1 - x0

  def header(self):
    """ Return Las Header

      :returns: Las Header
      :rtype: :class:`~ALASpy.header.Header`
    """
    return self._header

  def isReadMode(self):
    """ Return True if Las file is in 'read' mode

      :returns: True if Las file is in 'read' mode
      :rtype: bool
    """
    return self._fid.mode.startswith('r')

  def points(self):
    """ Return Point Data Records object

      :returns: Point Data Records object
      :rtype: :class:`~ALASpy.pointDataRecords.PointDataRecords`
    """
    return self._points

  def progress(self, value, info=None):
    """ Must be reimplemented in derived class to get the overal point
        reading progress

      :param value: progress value in [0, 1]
      :type  value: float
      :param info: info object
      :type  info: any
    """
    if info is not None:
      print '%s: Progress %s' % (str(info), value * 100.)
    else:
      print 'Progress %s' % (value * 100.)

  def write(self, points, **kargs):
    self._points.write(points, **kargs)

#===============================================================================

# I love Python!
LasObject.write.__func__.__doc__ = Points.write.__doc__
#===============================================================================
def main():
  import sys
  import numpy as np
  from core import VLRecord
  from IPython import embed
  trueExcepthook = sys.excepthook

  def excepthook(t, value, traceback):
    if t.__base__ in (LasException, IOError):
      print "Unhandled Exception <%s>: %s" % (t.__name__, value)
    else:
      trueExcepthook(type, value, traceback)

  sys.excepthook = excepthook

  l = LasObject(sys.argv[1])
#  print l.header().prettyWkt()
  
#  d = l.points().readTo(pointsDtype=np.ndarray, asFloat=False)
  d = l.points().readTo(pointsDtype=np.ndarray)
#  d = l.points().readTo(asFloat=True, fields='short',recsPerChunk=100000)
#  d = l.points().readTo(asFloat=True, fields='short')
#  d = l.points().readTo(asFloat=True, fields='short', withGPS=False, recStart=0)
#  d = l.points().readTo(asFloat=False, fields='all')
  embed()
#  raise SystemExit
  
  #data = l.records().read(pointsDtype=np.array(()), fields='short', unique=True, asFloat=False, recsPerChunk=3)
#  data = l.records().read(pointsDtype='/tmp/ccqq', fields='short', unique=True, asFloat=False, recsPerChunk=3)
  #data = l.records().read(pointsDtype=dict(), recsPerChunk=3)
  #data = l.records().read(pointsDtype=dict, recsPerChunk=3, fields='short', asFloat=True)
  #data = l.records().read(pointsDtype=dict, fields='short', asFloat=True)

#  if os.path.basename(l.filename()) == 'test.las':
#    embed()
#    sys.exit()
#  newl = LasObject('test.las', 'w', version=l.header().version(),
#    pointDataFormatID=l.header().pointDataFormatID())
#  newHeader = newl.header()
#  newHeader.setWkt(l.header().wkt())
#  #print newl.header().prettyWkt()
#  # Create new 'OGS' VLRecord 
#  payload = dict(d1="Some secret data", d2="More secret...")
#  ogs = VLRecord(newHeader, VLRecord.OGS, recordID=1,
#      description="A private VLR", data=payload)
#  print "NEW ogs VLRecord:", ogs
#  newHeader.addVarLengthRecord(ogs)
#  newl.write(d, offsets=l.header().offsets())
#  embed()

#===============================================================================
if __name__ == '__main__':
  main()
